package cn.iocoder.yudao.module.reading.service.recording;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.reading.controller.app.recording.vo.RecordingCreateReqVO;
import cn.iocoder.yudao.module.reading.controller.app.recording.vo.RecordingRespVO;
import cn.iocoder.yudao.module.reading.controller.app.recording.vo.RecordingUploadReqVO;
import cn.iocoder.yudao.module.reading.controller.app.recording.vo.RecordingUploadRespVO;
import cn.iocoder.yudao.module.reading.service.file.ReadingFileService;
import cn.iocoder.yudao.module.reading.framework.util.StaticResourceUrlUtils;
import cn.iocoder.yudao.module.reading.dal.dataobject.book.BookPageDO;
import cn.iocoder.yudao.module.reading.framework.util.StaticResourceUrlUtils;
import cn.iocoder.yudao.module.reading.dal.dataobject.book.PictureBookDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.bookset.BookSetDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.recording.UserRecordingDO;
import cn.iocoder.yudao.module.reading.dal.mysql.book.BookPageMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.book.PictureBookMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.bookset.BookSetMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.recording.UserRecordingMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.reading.enums.ErrorCodeConstants.*;

/**
 * 配音管理 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class RecordingServiceImpl implements RecordingService {

    @Resource
    private UserRecordingMapper userRecordingMapper;
    @Resource
    private PictureBookMapper pictureBookMapper;
    @Resource
    private BookPageMapper bookPageMapper;
    @Resource
    private BookSetMapper bookSetMapper;
    @Resource
    private ReadingFileService readingFileService;
    @Resource
    private StaticResourceUrlUtils staticResourceUrlUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RecordingUploadRespVO uploadRecording(Long userId, RecordingUploadReqVO uploadReqVO) {
        log.info("开始上传录音文件，用户ID: {}, 绘本ID: {}, 页面ID: {}, 文件名: {}, 文件大小: {}",
                userId, uploadReqVO.getBookId(), uploadReqVO.getPageId(),
                uploadReqVO.getFile() != null ? uploadReqVO.getFile().getOriginalFilename() : "null",
                uploadReqVO.getFile() != null ? uploadReqVO.getFile().getSize() : 0);

        try {
            // 1. 验证绘本和页面是否存在
            PictureBookDO book = pictureBookMapper.selectById(uploadReqVO.getBookId());
            if (book == null) {
                throw exception(PICTURE_BOOK_NOT_EXISTS);
            }

            // 验证页面ID（控制器已经处理了 pageNumber 到 pageId 的转换）
            if (uploadReqVO.getPageId() == null) {
                throw exception(BOOK_PAGE_NOT_EXISTS);
            }

            BookPageDO page = bookPageMapper.selectById(uploadReqVO.getPageId());
            if (page == null) {
                throw exception(BOOK_PAGE_NOT_EXISTS);
            }

            log.info("页面验证成功，页面ID: {}, 页码: {}", page.getId(), page.getPageNumber());

            // 2. 验证文件
            if (uploadReqVO.getFile() == null || uploadReqVO.getFile().isEmpty()) {
                throw exception(RECORDING_FILE_EMPTY);
            }

            // 验证录音时长
            if (uploadReqVO.getDuration() == null || uploadReqVO.getDuration() < 1 || uploadReqVO.getDuration() > 300) {
                throw exception(RECORDING_DURATION_INVALID);
            }

            // 验证文件大小和格式
            readingFileService.validateAudioFile(uploadReqVO.getFile(), 10 * 1024 * 1024); // 10MB限制

            // 3. 上传文件到存储服务（使用新版本方法，包含pageId）
            String audioUrl = readingFileService.uploadUserRecording(
                    userId, uploadReqVO.getBookId(), uploadReqVO.getPageId(), uploadReqVO.getFile());

            // 4. 检查是否已存在该页面的录音，如果存在则更新，否则创建新的
            log.info("检查用户录音记录，用户ID: {}, 页面ID: {}", userId, uploadReqVO.getPageId());
            UserRecordingDO existingRecording = userRecordingMapper.selectByUserIdAndPageId(userId, uploadReqVO.getPageId());

            if (existingRecording != null) {
                log.info("找到现有录音记录: ID={}, audioUrl={}", existingRecording.getId(), existingRecording.getAudioUrl());
            } else {
                log.info("未找到现有录音记录，将创建新记录");
            }

            UserRecordingDO recording;
            if (existingRecording != null) {
                // 更新现有录音
                log.info("找到现有录音记录，准备更新: ID={}, 原audioUrl={}",
                        existingRecording.getId(), existingRecording.getAudioUrl());

                // 保存旧文件路径，用于后续删除
                String oldAudioUrl = existingRecording.getAudioUrl();

                existingRecording.setAudioUrl(audioUrl);
                existingRecording.setDuration(uploadReqVO.getDuration());
                existingRecording.setRecordingQuality(uploadReqVO.getQuality());
                if (uploadReqVO.getIsPublic() != null) {
                    existingRecording.setIsShareable(uploadReqVO.getIsPublic());
                }

                log.info("准备更新录音记录到数据库: ID={}, 新audioUrl={}",
                        existingRecording.getId(), existingRecording.getAudioUrl());

                int updateResult = userRecordingMapper.updateById(existingRecording);
                log.info("数据库更新结果: 影响行数={}", updateResult);

                // 如果数据库更新成功，删除旧文件
                if (updateResult > 0 && oldAudioUrl != null && !oldAudioUrl.equals(audioUrl)) {
                    try {
                        readingFileService.deleteFile(oldAudioUrl);
                        log.info("成功删除旧录音文件: {}", oldAudioUrl);
                    } catch (Exception e) {
                        log.warn("删除旧录音文件失败，但不影响主流程: {}, 错误: {}", oldAudioUrl, e.getMessage());
                    }
                }

                if (updateResult > 0) {
                    // 验证更新是否成功
                    UserRecordingDO updatedRecording = userRecordingMapper.selectById(existingRecording.getId());
                    if (updatedRecording != null && audioUrl.equals(updatedRecording.getAudioUrl())) {
                        log.info("✅ 数据库验证成功，录音记录已更新: ID={}, audioUrl={}",
                                updatedRecording.getId(), updatedRecording.getAudioUrl());
                    } else {
                        log.error("❌ 数据库验证失败，录音记录更新未生效: ID={}", existingRecording.getId());
                        throw new RuntimeException("录音记录更新失败，数据库中数据未更新");
                    }
                } else {
                    log.error("❌ 数据库更新失败，影响行数为0: ID={}", existingRecording.getId());
                    throw new RuntimeException("录音记录更新失败，没有行被更新");
                }

                recording = existingRecording;
                log.info("更新录音记录成功，ID: {}", recording.getId());
            } else {
                // 创建新录音记录
                recording = new UserRecordingDO();
                recording.setUserId(userId);
                recording.setBookId(uploadReqVO.getBookId());
                recording.setPageId(uploadReqVO.getPageId());
                // 需要设置页码，从页面信息中获取
                if (page != null) {
                    recording.setPageNumber(page.getPageNumber());
                }
                recording.setAudioUrl(audioUrl);
                recording.setDuration(uploadReqVO.getDuration());
                recording.setRecordingQuality(uploadReqVO.getQuality() != null ? uploadReqVO.getQuality() : "medium");
                recording.setIsShareable(uploadReqVO.getIsPublic() != null ? uploadReqVO.getIsPublic() : false);

                log.info("准备插入录音记录到数据库: userId={}, bookId={}, pageId={}, audioUrl={}",
                        recording.getUserId(), recording.getBookId(), recording.getPageId(), recording.getAudioUrl());

                userRecordingMapper.insert(recording);
                log.info("创建录音记录成功，ID: {}", recording.getId());

                // 验证数据是否真正保存
                UserRecordingDO savedRecording = userRecordingMapper.selectById(recording.getId());
                if (savedRecording != null) {
                    log.info("✅ 数据库验证成功，录音记录已保存: ID={}, audioUrl={}",
                            savedRecording.getId(), savedRecording.getAudioUrl());
                } else {
                    log.error("❌ 数据库验证失败，录音记录未找到: ID={}", recording.getId());
                    throw new RuntimeException("录音记录保存失败，数据库中未找到记录");
                }
            }

            // 5. 构建响应
            RecordingUploadRespVO response = new RecordingUploadRespVO();
            response.setRecordingId(recording.getId());
            // 将相对路径转换为完整URL返回给前端
            response.setAudioUrl(staticResourceUrlUtils.toFullUrl(audioUrl));
            response.setDuration(recording.getDuration());
            response.setQuality(recording.getRecordingQuality());
            response.setFileSize(uploadReqVO.getFile().getSize()); // 从请求中获取文件大小
            response.setCreateTime(recording.getCreateTime());
            response.setStatus("success");
            response.setMessage("录音上传成功");

            log.info("✅ 录音上传处理完成，返回响应: recordingId={}, audioUrl={}",
                    response.getRecordingId(), response.getAudioUrl());

            return response;

        } catch (Exception e) {
            log.error("上传录音失败，用户ID: {}, 绘本ID: {}, 页面ID: {}, 错误信息: {}",
                    userId, uploadReqVO.getBookId(), uploadReqVO.getPageId(), e.getMessage(), e);

            throw exception(RECORDING_UPLOAD_FAILED, e.getMessage());
        }
    }

    @Override
    public Long createRecording(Long userId, RecordingCreateReqVO createReqVO) {
        // 验证绘本和页面是否存在
        PictureBookDO book = pictureBookMapper.selectById(createReqVO.getBookId());
        if (book == null) {
            throw exception(PICTURE_BOOK_NOT_EXISTS);
        }

        BookPageDO page = bookPageMapper.selectById(createReqVO.getPageId());
        if (page == null || !page.getBookId().equals(createReqVO.getBookId())) {
            throw exception(BOOK_PAGE_NOT_EXISTS);
        }

        // 将完整URL转换为相对路径存储到数据库
        String relativeAudioUrl = staticResourceUrlUtils.toRelativePath(createReqVO.getAudioUrl());

        // 检查是否已存在该页面的配音记录
        UserRecordingDO existingRecording = userRecordingMapper.selectByUserIdAndPageId(userId, createReqVO.getPageId());
        if (existingRecording != null) {
            // 如果已存在，则更新现有记录
            UserRecordingDO updateObj = UserRecordingDO.builder()
                    .id(existingRecording.getId())
                    .audioUrl(relativeAudioUrl)
                    .duration(createReqVO.getDuration())
                    .build();

            userRecordingMapper.updateById(updateObj);
            return existingRecording.getId();
        } else {
            // 创建新的配音记录
            UserRecordingDO recording = UserRecordingDO.builder()
                    .userId(userId)
                    .bookId(createReqVO.getBookId())
                    .pageId(createReqVO.getPageId())
                    .audioUrl(relativeAudioUrl)
                    .duration(createReqVO.getDuration())
                    .score(85) // 默认评分
                    .isShareable(false) // 默认不可分享
                    .recordingQuality("medium") // 默认中等质量
                    .build();
            
            userRecordingMapper.insert(recording);
            return recording.getId();
        }
    }

    @Override
    public void updateRecording(Long userId, Long recordingId, RecordingCreateReqVO updateReqVO) {
        UserRecordingDO recording = getRecording(recordingId);
        
        // 验证权限
        if (!recording.getUserId().equals(userId)) {
            throw exception(USER_RECORDING_NOT_EXISTS);
        }

        UserRecordingDO updateObj = UserRecordingDO.builder()
                .id(recordingId)
                .audioUrl(updateReqVO.getAudioUrl())
                .duration(updateReqVO.getDuration())
                .build();
        
        userRecordingMapper.updateById(updateObj);
    }

    @Override
    public UserRecordingDO getRecording(Long id) {
        UserRecordingDO recording = userRecordingMapper.selectById(id);
        if (recording == null) {
            throw exception(USER_RECORDING_NOT_EXISTS);
        }
        return recording;
    }

    @Override
    public RecordingRespVO getRecordingDetail(Long userId, Long recordingId) {
        UserRecordingDO recording = getRecording(recordingId);
        
        // 验证权限（只有自己的配音或可分享的配音才能查看）
        if (!recording.getUserId().equals(userId) && !recording.getIsShareable()) {
            throw exception(USER_RECORDING_NOT_EXISTS);
        }

        return buildRecordingResp(recording);
    }

    @Override
    public List<RecordingRespVO> getUserRecordings(Long userId, Integer limit) {
        List<UserRecordingDO> recordings = userRecordingMapper.selectByUserId(userId, limit);

        if (CollUtil.isEmpty(recordings)) {
            return new ArrayList<>();
        }

        return recordings.stream()
                .map(this::buildRecordingResp)
                .collect(Collectors.toList());
    }

    @Override
    public List<RecordingRespVO> getBookRecordings(Long userId, Long bookId) {
        List<UserRecordingDO> recordings = userRecordingMapper.selectByUserIdAndBookId(userId, bookId);
        
        if (CollUtil.isEmpty(recordings)) {
            return new ArrayList<>();
        }

        return recordings.stream()
                .map(this::buildRecordingResp)
                .collect(Collectors.toList());
    }

    @Override
    public RecordingRespVO getPageRecording(Long userId, Long pageId) {
        UserRecordingDO recording = userRecordingMapper.selectByUserIdAndPageId(userId, pageId);

        if (recording == null) {
            return null;
        }

        return buildRecordingResp(recording);
    }

    @Override
    public List<RecordingRespVO> getRecordings(Long bookId, Integer limit) {
        List<UserRecordingDO> recordings = userRecordingMapper.selectRecordings(bookId, limit);

        if (CollUtil.isEmpty(recordings)) {
            return new ArrayList<>();
        }

        return recordings.stream()
                .map(this::buildRecordingResp)
                .collect(Collectors.toList());
    }

    @Override
    public void deleteRecording(Long userId, Long recordingId) {
        int deletedCount = userRecordingMapper.softDeleteByUserIdAndId(userId, recordingId);
        if (deletedCount == 0) {
            throw exception(USER_RECORDING_NOT_EXISTS);
        }
    }

    @Override
    public Long countUserRecordings(Long userId) {
        return userRecordingMapper.countByUserId(userId);
    }

    /**
     * 构建配音响应对象
     */
    private RecordingRespVO buildRecordingResp(UserRecordingDO recording) {
        RecordingRespVO respVO = new RecordingRespVO();
        respVO.setId(recording.getId());
        respVO.setBookId(recording.getBookId());
        respVO.setPageId(recording.getPageId());
        // 将相对路径转换为完整URL
        respVO.setAudioUrl(staticResourceUrlUtils.toFullUrl(recording.getAudioUrl()));
        respVO.setDuration(recording.getDuration());
        respVO.setScore(recording.getScore());
        respVO.setIsShareable(recording.getIsShareable());
        respVO.setRecordingQuality(recording.getRecordingQuality());
        respVO.setCreateTime(recording.getCreateTime());

        // 设置绘本信息
        PictureBookDO book = pictureBookMapper.selectById(recording.getBookId());
        if (book != null) {
            RecordingRespVO.BookInfoVO bookInfo = new RecordingRespVO.BookInfoVO();
            bookInfo.setTitle(book.getTitle());
            // 将绘本封面相对路径转换为完整URL
            bookInfo.setCover(staticResourceUrlUtils.toFullUrl(book.getCover()));

            // 获取绘本集信息
            BookSetDO bookSet = bookSetMapper.selectById(book.getBookSetId());
            if (bookSet != null) {
                bookInfo.setBookSetTitle(bookSet.getTitle());
            }

            respVO.setBookInfo(bookInfo);
        }

        // 设置页面信息
        BookPageDO page = bookPageMapper.selectById(recording.getPageId());
        if (page != null) {
            RecordingRespVO.PageInfoVO pageInfo = new RecordingRespVO.PageInfoVO();
            pageInfo.setPageNumber(page.getPageNumber());
            // 将页面图片相对路径转换为完整URL
            pageInfo.setImageUrl(staticResourceUrlUtils.toFullUrl(page.getImageUrl()));
            pageInfo.setTextContent(page.getTextContent());
            respVO.setPageInfo(pageInfo);
        }

        return respVO;
    }

    @Override
    public Long getPageIdByBookIdAndPageNumber(Long bookId, Integer pageNumber) {
        log.info("根据绘本ID和页码查找页面ID，绘本ID: {}, 页码: {}", bookId, pageNumber);

        BookPageDO page = bookPageMapper.selectOne(new LambdaQueryWrapperX<BookPageDO>()
                .eq(BookPageDO::getBookId, bookId)
                .eq(BookPageDO::getPageNumber, pageNumber));

        if (page != null) {
            log.info("找到页面，页面ID: {}", page.getId());
            return page.getId();
        } else {
            log.warn("未找到页面，绘本ID: {}, 页码: {}", bookId, pageNumber);
            return null;
        }
    }

    @Override
    public boolean hasExistingRecording(Long userId, Long pageId) {
        log.info("检查用户录音是否存在，用户ID: {}, 页面ID: {}", userId, pageId);

        UserRecordingDO existingRecording = userRecordingMapper.selectByUserIdAndPageId(userId, pageId);
        boolean hasRecording = existingRecording != null;

        log.info("录音检查结果，用户ID: {}, 页面ID: {}, 是否存在: {}", userId, pageId, hasRecording);
        return hasRecording;
    }

}
